package cn.zhangxin.pethome.system.logininfo.service.impl;


import cn.zhangxin.pethome.base.service.impl.BaseServiceImpl;
import cn.zhangxin.pethome.jwt.PayloadData;
import cn.zhangxin.pethome.system.employee.domain.Employee;
import cn.zhangxin.pethome.system.employee.service.IEmployeeService;
import cn.zhangxin.pethome.system.logininfo.domain.LoginRo;
import cn.zhangxin.pethome.system.logininfo.domain.Logininfo;
import cn.zhangxin.pethome.system.logininfo.domain.LogininfoBO;
import cn.zhangxin.pethome.system.logininfo.domain.LogininfoVO;
import cn.zhangxin.pethome.system.logininfo.mapper.LogininfoMapper;
import cn.zhangxin.pethome.system.logininfo.service.ILogininfoService;
import cn.zhangxin.pethome.system.menu.domain.Menu;
import cn.zhangxin.pethome.system.menu.service.IMenuService;
import cn.zhangxin.pethome.system.user.domain.User;
import cn.zhangxin.pethome.system.user.mapper.UserMapper;
import cn.zhangxin.pethome.utils.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.Serializable;
import java.security.PrivateKey;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author zx
 * @since 2023-01-12
 */
@Service
public class LogininfoServiceImpl extends BaseServiceImpl<Logininfo> implements ILogininfoService {

    @Autowired
    private LogininfoMapper logininfoMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private IEmployeeService employeeService;
    @Autowired
    private ILogininfoService logininfoService;
    @Autowired
    private IMenuService iMenuService;
    @Autowired
    private UserMapper userMapper;
    @Value("${jwt.rsa.pri}")
    private String pri;

    @Override
    public AjaxResult account(LoginRo loginRo) {
        //当类型为空的时候
        if (loginRo.getType()==null){
            throw new BusinessException("非法访问");
        }
        //校验用户名是否为空
        if ("".equals(loginRo.getUsername().trim()) || loginRo.getUsername()==null){
            throw new BusinessException("用户名不能为空");
        }
        //校验密码是否为空
        if ("".equals(loginRo.getPassword().trim()) || loginRo.getPassword()==null){
            throw new BusinessException("密码不能为空");
        }
        //校验 电话 邮箱 账号是否为空
        Logininfo byUsername = logininfoMapper.findByUsername(loginRo.getUsername(),loginRo.getType());

        LogininfoBO logininfoBO = new LogininfoBO();//该类中没有密码和盐值
        BeanUtils.copyProperties(byUsername,logininfoBO);//拷贝

        if (byUsername==null){
            throw new BusinessException("用户名或者密码错误");
        }
        if (loginRo.getAutoLogin()){
            //校验 密码和账号是否匹配
            String salt = byUsername.getSalt();//获得盐值
            String MD5password = MD5Utils.encrypByMd5(loginRo.getPassword()+salt);
            if (!MD5password.equals(byUsername.getPassword())){
                throw new BusinessException("用户名或者密码错误");
            }
        }else {//传进来的是已经加密的密码，就不需要二次加密了
            if (!loginRo.getPassword().equals(byUsername.getPassword())){
                throw new BusinessException("用户名或者密码错误");
            }
        }

        return getJWTToken(loginRo, logininfoBO);
    }

    @Override
    public Logininfo findByUsername(String username, Integer type) {
        return logininfoMapper.findByUsername(username,type);
    }

    //redis方式获得token
    private AjaxResult getRedisToken(LoginRo loginRo, LogininfoBO logininfoBO) {
        String token = StrUtils.getComplexRandomString(128);
        //将用户信息存入redis
        redisTemplate.opsForValue().set(token,logininfoBO,30, TimeUnit.MINUTES);

        //将用户的权限存入redis
        //没有id查id
        Logininfo logininfo1 = logininfoService.findByUsername(loginRo.getUsername(), loginRo.getType());
        //获得员工的id
        Employee employee = employeeService.findOneByLogininfoId(logininfo1.getId());
        //通过员工角色中间表查询 员工角色
        List<String> permissionSn = employeeService.getPermissionSn(employee.getId());
        redisTemplate.opsForValue().set(token + "permission",permissionSn,30, TimeUnit.MINUTES);

        //封装返回的对象
        LogininfoVO logininfoVO = new LogininfoVO();
        logininfoVO.setToken(token);
        logininfoVO.setLogininfoBO(logininfoBO);
        return AjaxResult.success().setData(logininfoVO).setMsg("managerLogin");
    }
    //jwt方式获得token
    private AjaxResult getJWTToken(LoginRo loginRo, LogininfoBO logininfoBO){
        //没有id查id
        Logininfo logininfo1 = logininfoService.findByUsername(loginRo.getUsername(), loginRo.getType());

        //封装返回的对象
        LogininfoVO logininfoVO = new LogininfoVO();
        try {

            //构建载荷
            PayloadData payloadData = new PayloadData();
            //0是管理员
            if (logininfoBO.getType()==0){
                //获得员工的id
                Employee employee = employeeService.findOneByLogininfoId(logininfo1.getId());
                //通过员工角色中间表查询 员工角色权限
                List<String> permissionSn = employeeService.getPermissionSn(employee.getId());
                payloadData.setAdmin(employee);
                //消除重复值 设置权限
                payloadData.setPermissions(new HashSet<>(permissionSn));
                //设置menu
                //通过员工id查询角色
                List<Long> roles = employeeService.findRoleByEmpId(employee.getId());
                List<Menu> all = iMenuService.findAll();
                //构建自己的菜单树
                List<Long> menuByRole = iMenuService.findMenuByRoleIds(roles);
                //你自己
                List<Menu> c = new ArrayList<>();
                for (Menu menu : all) {
                    for (Long aLong : menuByRole) {
                        if(menu.getId().equals(aLong)){
                            c.add(menu);
                        }
                    }
                }
                //父亲的id
                List<Long> parent = c.stream()
                        .map(Menu::getParentId)  //只要ParentId
                        .distinct() //去除重复值
                        .collect(Collectors.toList());

                // 取父级
                List<Menu> p = new ArrayList<>();
                for (Menu menu : all) {
                    for (Long aLong : parent) {
                        if(menu.getId().equals(aLong)){
                            p.add(menu);
                        }
                    }
                };

                p.forEach(menu -> {
                    c.forEach(menu1 -> {
                        if(menu1.getParentId().equals(menu.getId())){
                            List<Menu> children = menu.getChildren();
                            children.add(menu1);
                        }
                    });
                });
                payloadData.setMenus(p);
            }else{//1是用户
                Long id = logininfo1.getId();
                payloadData.setUser(userMapper.findOneByLogininfoIdUser(id));
            }

            //获取token
            PrivateKey privateKey = RsaUtils.getPrivateKey(JwtUtils.class.getClassLoader().getResource(pri).getFile());
            String token = JwtUtils.generateTokenExpireInMinutes(payloadData, privateKey, 30);

            //设置token和用户信息
            System.out.println(token);

            logininfoVO.setToken(token);
            logininfoVO.setLogininfoBO(logininfoBO);
            logininfoVO.setEmployee(payloadData.getAdmin());
            logininfoVO.setUser(payloadData.getUser());
            logininfoVO.setMenus(payloadData.getMenus());
            logininfoVO.setPermissions(payloadData.getPermissions());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return AjaxResult.success().setData(logininfoVO).setMsg("managerLogin");
    }
}
